#include "Highlighting.h"

#include "SharedConstants.h"
#include "HeightMap.h"
#include "Model3D.h"
#include "HeightMapCoordinates.h"
#include "WorldInfoController.h"
#include "FindWaterAreas.h"
#include "Ground.h"

namespace Highlighting
  {
  // Generates simple plane. used for ferris wheel since it is BIG
  std::shared_ptr<Model3D> GetCellsHighlighting(const HeightMap& i_heightmap, const TVector3& i_coords, size_t i_spread)
    {
    TVector3 world_point;

    std::shared_ptr<Model3D> model = std::make_shared<Model3D>();
    TCell cell = ConvertTVectorToTCell(TVector2(i_coords.X(), i_coords.Y()));

    size_t max_x = i_heightmap.GetSizeX();
    size_t max_y = i_heightmap.GetSizeY();
    std::vector<THMapPoint> points;
    for(size_t x = cell.first - i_spread; x <= cell.first + 1 + i_spread; x++)
      {
      for(size_t y = cell.second - i_spread; y <= cell.second + 1 + i_spread; y++)
        {
        if(x >= 0 && y >= 0 && x < max_x && y < max_y)
          points.push_back(THMapPoint(x, y));
        }
      }

    double max_v = 0;
    for(THMapPoint point : points)
      {
      max_v = std::max(max_v, i_heightmap.Get(point.first, point.second));
      }
    double height = GroundConstants::ORIGIN_Z +
      GroundConstants::CELL_SIZE * max_v +
      0.3;

    /*
    1 2
    3 4

    triangles: 1-2-3, 2-4-3
    */
    auto point1 = model->AddPoint(HeightMapUtils::ConvertHMapPointToTVector(cell.first - i_spread, cell.second - i_spread, height));
    auto point2 = model->AddPoint(HeightMapUtils::ConvertHMapPointToTVector(cell.first - i_spread, cell.second + 1 + i_spread, height));
    auto point3 = model->AddPoint(HeightMapUtils::ConvertHMapPointToTVector(cell.first + 1 + i_spread, cell.second - i_spread, height));
    auto point4 = model->AddPoint(HeightMapUtils::ConvertHMapPointToTVector(cell.first + 1 + i_spread, cell.second + 1 + i_spread, height));

    Triangle3DID tr1 = model->AddTriangle(point1, point2, point3);
    Triangle3DID tr2 = model->AddTriangle(point2, point4, point3);

    // Textures
    tr1.GetTriangle().SetPointsUV(TVector2(0, 0), TVector2(1, 0), TVector2(0, 1));
    tr2.GetTriangle().SetPointsUV(TVector2(1, 0), TVector2(1, 1), TVector2(0, 1));

    return model;
    }

  std::shared_ptr<Model3D> GetHighlightedModel(const TTriangle3& i_triangle, const Ground& i_ground)
  {
  std::vector<TTriangle3> triangles;
  TTriangle3 triangle1 = i_triangle;

  std::shared_ptr<Model3D> p_model = nullptr;
  p_model.reset(new Model3D());

    triangles.push_back(triangle1);
    TTriangle3 triangle2;

    const bool left_triangle = triangle1.V[0].X() > triangle1.V[1].X() && triangle1.V[1].Y() < triangle1.V[2].Y();
    if(left_triangle)
      {
      const double x_coord = triangle1.V[0].X();
      const double y_coord = triangle1.V[2].Y();
      std::pair<size_t, size_t> coord = i_ground.GetCellPosition(TVector2(x_coord, y_coord));
      const double z_coord = GroundConstants::ORIGIN_Z + GroundConstants::CELL_SIZE * i_ground.GetHeightMap().Get(coord.first, coord.second);
      const TVector3 point(x_coord, y_coord, z_coord);
      triangle2.V[0] = point; 
      triangle2.V[1] = triangle1.V[0];
      triangle2.V[2] = triangle1.V[2];
      }
    else
      {
      const double x_coord = triangle1.V[2].X();
      const double y_coord = triangle1.V[1].Y();
      std::pair<size_t, size_t> coord = i_ground.GetCellPosition(TVector2(x_coord, y_coord));
      const double z_coord = GroundConstants::ORIGIN_Z + GroundConstants::CELL_SIZE * i_ground.GetHeightMap().Get(coord.first, coord.second);
      const TVector3 point(x_coord, y_coord, z_coord);
      triangle2.V[0] = triangle1.V[1];
      triangle2.V[1] = point;
      triangle2.V[2] = triangle1.V[2];
      }

    triangles.push_back(triangle2);

    std::vector<Point3DID> points; 
    for(size_t j = 0; j < 2; ++j)
      {
      for(size_t i = 0; i < 3; ++i)
        {
        const Point3DID point = p_model->AddPoint(triangles[j].V[i].X(), triangles[j].V[i].Y(), triangles[j].V[i].Z());
        points.push_back(point);
        }
      }

    p_model->AddTriangle(points[0], points[1], points[2]);
    p_model->AddTriangle(points[3], points[4], points[5]);

    // set texture coordinates
    if (left_triangle)
      {
      auto it = p_model->TrianglesMutable().begin();
      it -> SetPointsUV(TVector2(0,1), TVector2(0,0), TVector2(1,0));
      ++it;
      it -> SetPointsUV(TVector2(1,1), TVector2(1,0), TVector2(0,1));
      }
    else
      {
      auto it = p_model->TrianglesMutable().begin();
      it -> SetPointsUV(TVector2(1,1), TVector2(1,0), TVector2(0,1));
      ++it;
      it -> SetPointsUV(TVector2(0,1), TVector2(0,0), TVector2(1,0));
      }

    return p_model;
  }


  }